﻿// Copyright (c) 2009, Heiko Wundram (modelnine@h8me.eu).
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
// conditions are met:
//
// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
//   in the documentation and/or other materials provided with the distribution.
// * Neither the name of Heiko Wundram (h8me.eu) nor the names of its contributors may be used to endorse or promote products
//   derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

using System;
using System.Collections.Generic;
using System.Text;

namespace eu.h8me.Parsing.ParserLib {

    /// <summary>
    /// Helper class signalling an exception that was encountered during the execution of a parse.
    /// </summary>
    public sealed class ParseFailedException : Exception {

        // Data.
        private readonly IEnumerable<Symbol> _ExpectedSymbols;
        private readonly Token _Token;

        /// <summary>
        /// Initialize a new parsing exception with the specified error message.
        /// </summary>
        /// <param name="msg">Message to attach to the exception.</param>
        /// <param name="symbs">Symbols that were expected.</param>
        /// <param name="tok">Failing token.</param>
        internal ParseFailedException(string msg, IEnumerable<Symbol> symbs, Token tok)
            : base(msg) {
            // Store data.
            _ExpectedSymbols = symbs;
            _Token = tok;
        }

        /// <summary>
        /// Fetch expected symbols.
        /// </summary>
        public IEnumerable<Symbol> ExpectedSymbols {
            get {
                // Return list of expected symbols.
                return _ExpectedSymbols;
            }
        }

        /// <summary>
        /// Fetch found token.
        /// </summary>
        public Token Token {
            get {
                // Return found token.
                return _Token;
            }
        }

        /// <summary>
        /// Build string message describing exception.
        /// </summary>
        /// <returns>Message of this exception.</returns>
        public override string ToString() {
            // Format expected symbols.
            StringBuilder expected = new StringBuilder();
            foreach( Symbol symb in _ExpectedSymbols )
                // Format message.
                expected.AppendFormat("{0} or ", symb.Name);

            // Build resulting string.
            return String.Format("Expected {0}, but found {1} at {2}: {3}", expected.ToString(0, expected.Length - 4), _Token.Symbol.Name, _Token.Position.ToString(), base.ToString());
        }

    }

    /// <summary>
    /// Helper class to store info on a failed merge.
    /// </summary>
    public sealed class MergeFailedException : Exception {

        // Data.
        private readonly Token _Token;

        /// <summary>
        /// Initialize a new merge failed exception.
        /// </summary>
        /// <param name="msg">Message for the exception.</param>
        /// <param name="tok">Token that the merge failed on.</param>
        internal MergeFailedException(string msg, Token tok)
            : base(msg) {
            // Store data.
            _Token = tok;
        }

        /// <summary>
        /// Fetch the token that caused the failed merge.
        /// </summary>
        public Token Token {
            get {
                // Access failing token.
                return _Token;
            }
        }

        /// <summary>
        /// Build string message describing exception.
        /// </summary>
        /// <returns>String form of exception.</returns>
        public override string ToString() {
            // Build message.
            return String.Format("Merged on {0} at {1}: {2}", _Token.Symbol.Name, _Token.Position.ToString(), base.ToString());
        }

    }

    /// <summary>
    /// Helper class signalling to the parser that the specified reduction path that is currently being taken is to be
    /// ignored.
    /// </summary>
    public sealed class FailReductionException : Exception {

        /// <summary>
        /// Initialize a new reduction failure exception.
        /// </summary>
        public FailReductionException()
            : base("Reduction to be ignored") {
            // No specific construction.
        }

    }

}
